package br.edu.infnet.avaliacao.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.EntityManager;

import br.com.caelum.vraptor.Get;
import br.com.caelum.vraptor.Post;
import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;
import br.com.caelum.vraptor.Validator;
import br.com.caelum.vraptor.validator.ValidationMessage;
import br.com.caelum.vraptor.validator.Validations;
import br.edu.infnet.avaliacao.dao.DAO;
import br.edu.infnet.avaliacao.model.DivisaoQuestionario;
import br.edu.infnet.avaliacao.model.Questao;
import br.edu.infnet.avaliacao.model.Questionario;

@Resource
public class QuestionarioController extends AbstractController<Questionario>{
	
	public QuestionarioController(EntityManager entityManager, Validator validator, Result result) {
		super(entityManager, validator, result , Questionario.class);
	}
	
	
	/*
	 * Sobre-escrita de método necessária por causa da Anotação
	 */
    @Get("/questionario")
    public List<Questionario> principal() {
        return super.principal();
    }

    
    /*
     * Inclusão
     */
    @Get("/questionario/form")
    public void form() {
    	// redirecionamento padrão
    }
    
    /*
     * Alteração
     */
    @Get("/questionario/form/{questionarioId}") // 
    public void form(String questionarioId) {
    	
    	Questionario questionario = this.getModelById(questionarioId); 
    	
    	result.include("questionario", questionario);
    	
    }
    
    /*
     * Salvamento
     */
    @Post("/questionario/salvar")
    public void salvar(final Questionario questionario, boolean alteracao) {
    	DAO<Questionario> dao = new DAO<Questionario>(Questionario.class , entityManager);

    	validator.checking(new Validations() {{
    		if (that(questionario != null, "questionario", "questionario.nulo")) {
    			
    			if (that(questionario.getId() != null && !questionario.getId().isEmpty(), "questionario.id", "id.vazio"))
    			{
    				that(questionario.getId().length() <= 20, "questionario.id", "tamanho.maximo", "ID", 20);
    			}
    				
    			if (that(questionario.getObjetivo() != null && !questionario.getObjetivo().isEmpty(), "questionario.objetivo", "objetivo.vazio"))
    			{
    				that(questionario.getObjetivo().length() <= 200, "questionario.objetivo", "tamanho.maximo", "Objetivo", 200);
    			}
    		}
        }});
    	    	
    	validator.onErrorUsePageOf(QuestionarioController.class).form();
    	
    	questionario.setId(questionario.getId().toUpperCase());
    	
    	if (alteracao)
    	{
    		dao.alterar(questionario);
    		result.redirectTo(QuestionarioController.class).principal();
    	}
    	else
    	{
    		dao.salvar(questionario);

    		// redireciona para o cadastro da divisão
    		result.redirectTo(QuestionarioController.class).subdivisao(questionario.getId(), 0);
    	}

		        
    }
    
    /*
     * Exclusão
     */
    @Get("/questionario/excluir/{questionarioId}")
    public void excluir(String questionarioId) {
    	
    	// obtem o questionario e valida
    	Questionario questionario = this.getModelById(questionarioId);
    	
    	// Obtem as Divisões do Questionário
    	DAO<DivisaoQuestionario> divQuestDao = new DAO<DivisaoQuestionario>(DivisaoQuestionario.class, entityManager);
    	List<DivisaoQuestionario> divQuestList = divQuestDao.getLista("questionario", questionario);
    	
    	for (DivisaoQuestionario divisaoQuestionario : divQuestList)
    	{
    		//remove as Divisões do Questionário
    		divQuestDao.deletar(divisaoQuestionario);
		}
    	
    	//remove o questionario
    	DAO<Questionario> questionarioDao = new DAO<Questionario>(Questionario.class , entityManager);
    	questionarioDao.deletar(questionario);
    	
    	result.redirectTo(QuestionarioController.class).principal();

    }
    
    /*
     * Inclusão/Alteração da subdivisão do questionario
     */
    @Get("/questionario/subdivisao/{questionarioId}/{divisaoId}")
    public void subdivisao(String questionarioId, int divisaoId) {
    	
    	Questionario questionario = this.getModelById(questionarioId);    	
        result.include("questionario", questionario);
        
        DivisaoQuestionario divisaoQuestionario = null;
        if (divisaoId > 0)
        {
        	DAO<DivisaoQuestionario> subDivDao = new DAO<DivisaoQuestionario>(DivisaoQuestionario.class, entityManager);
        	
        	divisaoQuestionario = subDivDao.getObject("id", divisaoId);
        	
        	if (divisaoQuestionario == null)
        	{
        		validator.add(new ValidationMessage("id.invalido", "divisaoQuestionario"));
        	}
        	
        	validator.onErrorForwardTo(this).principal();
        	
        	result.include("divisaoQuestionario", divisaoQuestionario);
        }
        
        //TODO: Mudar o método de obter as questões disponíveis, utilizar subquery.
        
        //Obtem as questões que já foram utilizadas neste questionario
        List<Questao> questoesUtilizadas = new ArrayList<Questao>();
        Set<DivisaoQuestionario> divisoes = questionario.getDivisaoQuestionarios();
        for (DivisaoQuestionario divisao : divisoes)
        {
			if (divisaoId != divisao.getId()) //só adiciona se o id da divisão que está sendo editada for diferente
			{
				for (Questao questao : divisao.getQuestoes())
				{
					questoesUtilizadas.add(questao);
				}
			}
		}
        
        // Obtem todas as questões diponíveis
        DAO<Questao> dao = new DAO<Questao>(Questao.class, entityManager);
        List<Questao> questaoTodas = dao.getLista();
        
        // Lista que questões que aparecerão para o usuário
        Map<Questao, Boolean> questaoList = new HashMap<Questao, Boolean>();
        
        // só adiona na lista o que não foi utilizado
        for (Questao questao : questaoTodas)
        {
			boolean utilizada = false;
			for (Questao questaoUtilizada : questoesUtilizadas)
			{
				if (questao.getId() == questaoUtilizada.getId())
				{
					utilizada = true;
					break;
				}
			}
			
			if (!utilizada)
			{
				boolean marcada = false;
				if (divisaoId > 0) // marca as questões que já estavam na divisão
				{
					for (Questao questaoDaDivisao : divisaoQuestionario.getQuestoes())
					{
						if (questao.getId() == questaoDaDivisao.getId())
						{
							marcada = true;
							break;
						}
					}
				}
				
				questaoList.put(questao, marcada);
			}
		}
        
        result.include("questaoList", questaoList);
        
    }
    
    /*
     * Salvamento da subdivisão do questionario
     */
    @Post("/questionario/subdivisao/salvar")
    public void salvarSubdivisao(String questionarioId, final DivisaoQuestionario divisaoQuestionario, List<Integer> questoes) {
    	
    	// obtem o questionario
    	final Questionario questionario = this.getModelById(questionarioId);
    	
    	Set<Questao> questoesSubDiv = new HashSet<Questao>();
    	
    	// validação do questionario
		if (questoes == null || questoes.size() == 0)
		{			
			validator.add(new ValidationMessage("questoes.vazio", "questionario"));
		}
		else
		{
	    	//DAO das Questoes
	    	DAO<Questao> questaoDao = new DAO<Questao>(Questao.class, entityManager);
	    	
	    	for (Integer questaoId : questoes)
	    	{
				Questao questao = questaoDao.getObject("id", questaoId);
				
				// validação da questao
				if (questao == null)
				{
					validator.add(new ValidationMessage("id.invalido", "questao"));
					break;
				}
				
				questoesSubDiv.add(questao);
			}
		}
		
		// validação dos campos da Divisão do Questionário
		
    	validator.checking(new Validations() {{
    		if (that(divisaoQuestionario != null &&
					divisaoQuestionario.getDescricao() != null && 
					!divisaoQuestionario.getDescricao().isEmpty(), 
					"descricao.vazia", "divisaoQuestionario"))
			{
				that(divisaoQuestionario.getDescricao().length() <= 100, "divisaoQuestionario.descricao", "tamanho.maximo", "Descrição", 100);
			}
        }});
        
		
    	// redireciona para o cadastro em caso de erro
    	validator.onErrorForwardTo(this).subdivisao(questionarioId, 
    			(divisaoQuestionario == null || divisaoQuestionario.getId() == null ? 0 : divisaoQuestionario.getId()));
    	    	
    	
    	//Salva a Divisão de Questionários
    	DAO<DivisaoQuestionario> divQuestDao = new DAO<DivisaoQuestionario>(DivisaoQuestionario.class, entityManager);
    	
    	divisaoQuestionario.setQuestionario(questionario);
    	divisaoQuestionario.setQuestoes(questoesSubDiv);
    	
    	if (divisaoQuestionario.getId() == null) // inclusao
    	{
    		divQuestDao.salvar(divisaoQuestionario);
    	}
    	else // alteração
    	{
    		divQuestDao.alterar(divisaoQuestionario);
    	}
    
    	
    	// redireciona para a página principal
    	result.redirectTo(QuestionarioController.class).form(questionarioId);
    }
    
    
    /*
     * Exclusão de Subdivisão
     */
    @Get("/questionario/subdivisao/excluir/{questionarioId}/{divisaoId}")
    public void excluirSubdivisao(String questionarioId, int divisaoId) {
    	
    	// obtem o questionario e valida
    	Questionario questionario = this.getModelById(questionarioId);
    	
    	
    	DAO<DivisaoQuestionario> divQuestDao = new DAO<DivisaoQuestionario>(DivisaoQuestionario.class, entityManager);
    	
    	// obtem o questionario e valida
    	DivisaoQuestionario divisao = divQuestDao.getObject("id", divisaoId);
    	
    	if (divisao == null)
    	{
    		validator.add(new ValidationMessage("id.invalido", "divisaoQuestionario"));
    	}
    	
    	validator.onErrorForwardTo(this).form(questionario.getId());
    	
    	divQuestDao.deletar(divisao);
    	
    	result.redirectTo(QuestionarioController.class).form(questionario.getId());

    }

}
